import { BlockActionSeparator } from "@/components";
import MdiDeleteForeverOutline from "@/components/icon/MdiDeleteForeverOutline.vue";
import ToolboxItem from "@/components/toolbox/ToolboxItem.vue";
import { i18n } from "@/locales";
import {
  isActive,
  mergeAttributes,
  PluginKey,
  PMNode,
  VueNodeViewRenderer,
  type Editor,
  type Range,
} from "@/tiptap";
import type { EditorState } from "@/tiptap/pm";
import type {
  DragSelectionNodeType,
  ExtensionOptions,
  NodeBubbleMenuType,
} from "@/types";
import { deleteNode } from "@/utils";
import type { ImageOptions } from "@tiptap/extension-image";
import TiptapImage from "@tiptap/extension-image";
import { Plugin } from "@tiptap/pm/state";
import { markRaw } from "vue";
import MdiFileImageBox from "~icons/mdi/file-image-box";
import MdiFormatAlignCenter from "~icons/mdi/format-align-center";
import MdiFormatAlignJustify from "~icons/mdi/format-align-justify";
import MdiFormatAlignLeft from "~icons/mdi/format-align-left";
import MdiFormatAlignRight from "~icons/mdi/format-align-right";
import MdiLink from "~icons/mdi/link";
import MdiLinkVariant from "~icons/mdi/link-variant";
import MdiShare from "~icons/mdi/share";
import MdiTextBoxEditOutline from "~icons/mdi/text-box-edit-outline";
import BubbleItemImageAlt from "./BubbleItemImageAlt.vue";
import BubbleItemImageHref from "./BubbleItemImageHref.vue";
import BubbleItemVideoLink from "./BubbleItemImageLink.vue";
import BubbleItemImageSize from "./BubbleItemImageSize.vue";
import ImageView from "./ImageView.vue";

export const IMAGE_BUBBLE_MENU_KEY = new PluginKey("imageBubbleMenu");

const Image = TiptapImage.extend<ExtensionOptions & Partial<ImageOptions>>({
  fakeSelection: true,

  inline() {
    return true;
  },

  group() {
    return "inline";
  },

  addAttributes() {
    return {
      ...this.parent?.(),
      width: {
        default: undefined,
        parseHTML: (element) => {
          const width =
            element.getAttribute("width") || element.style.width || null;
          return width;
        },
        renderHTML: (attributes) => {
          return {
            width: attributes.width,
          };
        },
      },
      height: {
        default: undefined,
        parseHTML: (element) => {
          const height =
            element.getAttribute("height") || element.style.height || null;
          return height;
        },
        renderHTML: (attributes) => {
          return {
            height: attributes.height,
          };
        },
      },
      href: {
        default: null,
        parseHTML: (element) => {
          const href = element.getAttribute("href") || null;
          return href;
        },
        renderHTML: (attributes) => {
          return {
            href: attributes.href,
          };
        },
      },
      style: {
        renderHTML() {
          return {
            style: "display: inline-block",
          };
        },
      },
    };
  },

  addNodeView() {
    return VueNodeViewRenderer(ImageView);
  },

  parseHTML() {
    return [
      {
        tag: this.options.allowBase64
          ? "img[src]"
          : 'img[src]:not([src^="data:"])',
      },
    ];
  },

  addProseMirrorPlugins() {
    return [
      new Plugin({
        key: new PluginKey("imagePaste"),
        props: {
          handlePaste: (view, event) => {
            const items = Array.from(event.clipboardData?.items || []);
            const imageItems = items.filter((item) => item.type.indexOf("image") !== -1);

            if (imageItems.length === 0) {
              return false;
            }

            event.preventDefault();

            // 使用 Promise.all 处理所有图片
            const uploadPromises = imageItems.map(async (item) => {
              const file = item.getAsFile();
              if (!file) return;

              // 创建本地预览 URL（存储在浏览器内存中）
              const tempUrl = URL.createObjectURL(file);

              // 获取当前光标位置
              const { selection } = view.state;
              const position = selection.$anchor.pos;

              // 插入临时图片节点（显示预览）
              const imageNode = view.state.schema.nodes.image;
              if (imageNode) {
                const tempNode = imageNode.create({
                  src: tempUrl,
                  alt: file.name,
                });

                const transaction = view.state.tr.insert(position, tempNode);
                view.dispatch(transaction);

                // 如果配置了上传处理器，则上传文件
                const uploadHandler = this.options.uploadHandler;
                if (uploadHandler && typeof uploadHandler === 'function') {
                  try {
                    // 调用上传处理器
                    const uploadedUrl = await uploadHandler(file);
                    
                    if (uploadedUrl) {
                      // 上传成功，替换临时 URL 为真实 URL
                      setTimeout(() => {
                        const { state } = view;
                        const { doc } = state;
                        let found = false;
                        
                        // 查找包含临时 URL 的图片节点
                        doc.descendants((node, pos) => {
                          if (!found && node.type.name === 'image' && node.attrs.src === tempUrl) {
                            // 更新节点的 src 属性
                            const tr = state.tr.setNodeMarkup(pos, undefined, {
                              ...node.attrs,
                              src: uploadedUrl,
                            });
                            view.dispatch(tr);
                            
                            // 延迟释放临时 Blob URL，确保新 URL 已经加载
                            setTimeout(() => {
                              URL.revokeObjectURL(tempUrl);
                            }, 1000);
                            
                            found = true;
                            return false;
                          }
                        });
                      }, 100);
                    } else {
                      // 上传失败，删除临时图片节点
                      setTimeout(() => {
                        const { state } = view;
                        const { doc } = state;
                        let found = false;
                        
                        doc.descendants((node, pos) => {
                          if (!found && node.type.name === 'image' && node.attrs.src === tempUrl) {
                            const tr = state.tr.delete(pos, pos + node.nodeSize);
                            view.dispatch(tr);
                            URL.revokeObjectURL(tempUrl);
                            found = true;
                            return false;
                          }
                        });
                      }, 100);
                    }
                  } catch (error) {
                    console.error('上传图片失败:', error);
                    // 上传失败，删除临时图片节点
                    setTimeout(() => {
                      const { state } = view;
                      const { doc } = state;
                      let found = false;
                      
                      doc.descendants((node, pos) => {
                        if (!found && node.type.name === 'image' && node.attrs.src === tempUrl) {
                          const tr = state.tr.delete(pos, pos + node.nodeSize);
                          view.dispatch(tr);
                          URL.revokeObjectURL(tempUrl);
                          found = true;
                          return false;
                        }
                      });
                    }, 100);
                  }
                }
              }
            });

            // 不等待上传完成，立即返回 true
            return true;
          },
          handleDrop: (view, event, slice, moved) => {
            // 处理拖拽上传
            if (!event.dataTransfer || moved) {
              return false;
            }

            const files = Array.from(event.dataTransfer.files || []);
            const imageFiles = files.filter((file) => file.type.indexOf("image") !== -1);

            if (imageFiles.length === 0) {
              return false;
            }

            event.preventDefault();

            const coordinates = view.posAtCoords({
              left: event.clientX,
              top: event.clientY,
            });

            if (!coordinates) return false;

            imageFiles.forEach(async (file) => {
              // 创建本地预览 URL
              const tempUrl = URL.createObjectURL(file);

              // 插入临时图片节点
              const imageNode = view.state.schema.nodes.image;
              if (imageNode) {
                const tempNode = imageNode.create({
                  src: tempUrl,
                  alt: file.name,
                });

                const transaction = view.state.tr.insert(coordinates.pos, tempNode);
                view.dispatch(transaction);

                // 如果配置了上传处理器，则上传文件
                const uploadHandler = this.options.uploadHandler;
                if (uploadHandler && typeof uploadHandler === 'function') {
                  try {
                    const uploadedUrl = await uploadHandler(file);
                    
                    if (uploadedUrl) {
                      // 上传成功，替换临时 URL
                      setTimeout(() => {
                        const { state } = view;
                        const { doc } = state;
                        let found = false;
                        
                        doc.descendants((node, pos) => {
                          if (!found && node.type.name === 'image' && node.attrs.src === tempUrl) {
                            const tr = state.tr.setNodeMarkup(pos, undefined, {
                              ...node.attrs,
                              src: uploadedUrl,
                            });
                            view.dispatch(tr);
                            
                            // 延迟释放临时 URL
                            setTimeout(() => {
                              URL.revokeObjectURL(tempUrl);
                            }, 1000);
                            
                            found = true;
                            return false;
                          }
                        });
                      }, 100);
                    } else {
                      // 上传失败，删除临时图片
                      setTimeout(() => {
                        const { state } = view;
                        const { doc } = state;
                        let found = false;
                        
                        doc.descendants((node, pos) => {
                          if (!found && node.type.name === 'image' && node.attrs.src === tempUrl) {
                            const tr = state.tr.delete(pos, pos + node.nodeSize);
                            view.dispatch(tr);
                            URL.revokeObjectURL(tempUrl);
                            found = true;
                            return false;
                          }
                        });
                      }, 100);
                    }
                  } catch (error) {
                    console.error('拖拽上传失败:', error);
                    setTimeout(() => {
                      const { state } = view;
                      const { doc } = state;
                      let found = false;
                      
                      doc.descendants((node, pos) => {
                        if (!found && node.type.name === 'image' && node.attrs.src === tempUrl) {
                          const tr = state.tr.delete(pos, pos + node.nodeSize);
                          view.dispatch(tr);
                          URL.revokeObjectURL(tempUrl);
                          found = true;
                          return false;
                        }
                      });
                    }, 100);
                  }
                }
              }
            });

            return true;
          },
        },
      }),
    ];
  },
  addOptions() {
    return {
      ...this.parent?.(),
      uploadHandler: null, // 上传处理器函数
      getToolboxItems({ editor }: { editor: Editor }) {
        return [
          {
            priority: 10,
            component: markRaw(ToolboxItem),
            props: {
              editor,
              icon: markRaw(MdiFileImageBox),
              title: i18n.global.t("editor.common.image"),
              action: () => {
                editor
                  .chain()
                  .focus()
                  .insertContent([{ type: "image", attrs: { src: "" } }])
                  .run();
              },
            },
          },
        ];
      },
      getCommandMenuItems() {
        return {
          priority: 170,
          icon: markRaw(MdiFileImageBox),
          title: "editor.extensions.commands_menu.image",
          keywords: ["image", "tupian"],
          command: ({ editor, range }: { editor: Editor; range: Range }) => {
            editor
              .chain()
              .focus()
              .deleteRange(range)
              .insertContent([
                { type: "image", attrs: { src: "" } },
                { type: "paragraph", content: "" },
              ])
              .run();
          },
        };
      },
      getBubbleMenu({ editor }: { editor: Editor }): NodeBubbleMenuType {
        return {
          pluginKey: IMAGE_BUBBLE_MENU_KEY,
          shouldShow: ({ state }: { state: EditorState }): boolean => {
            return isActive(state, Image.name);
          },
          options: {
            placement: "top-start",
          },
          items: [
            {
              priority: 10,
              component: markRaw(BubbleItemImageSize),
            },
            {
              priority: 20,
              props: {
                isActive: () => editor.isActive({ textAlign: "left" }),
                icon: markRaw(MdiFormatAlignLeft),
                action: () => handleSetTextAlign(editor, "left"),
              },
            },
            {
              priority: 30,
              props: {
                isActive: () => editor.isActive({ textAlign: "center" }),
                icon: markRaw(MdiFormatAlignCenter),
                action: () => handleSetTextAlign(editor, "center"),
              },
            },
            {
              priority: 40,
              props: {
                isActive: () => editor.isActive({ textAlign: "right" }),
                icon: markRaw(MdiFormatAlignRight),
                action: () => handleSetTextAlign(editor, "right"),
              },
            },
            {
              priority: 50,
              props: {
                isActive: () => editor.isActive({ textAlign: "justify" }),
                icon: markRaw(MdiFormatAlignJustify),
                action: () => handleSetTextAlign(editor, "justify"),
              },
            },
            {
              priority: 60,
              component: markRaw(BlockActionSeparator),
            },
            {
              priority: 70,
              props: {
                icon: markRaw(MdiLinkVariant),
                title: i18n.global.t("editor.common.button.edit_link"),
                action: () => {
                  return markRaw(BubbleItemVideoLink);
                },
              },
            },
            {
              priority: 80,
              props: {
                icon: markRaw(MdiShare),
                title: i18n.global.t("editor.common.tooltip.open_link"),
                action: () => {
                  window.open(editor.getAttributes(Image.name).src, "_blank");
                },
              },
            },
            {
              priority: 90,
              props: {
                icon: markRaw(MdiTextBoxEditOutline),
                title: i18n.global.t("editor.extensions.image.edit_alt"),
                action: () => {
                  return markRaw(BubbleItemImageAlt);
                },
              },
            },
            {
              priority: 100,
              props: {
                icon: markRaw(MdiLink),
                title: i18n.global.t("editor.extensions.image.edit_href"),
                action: () => {
                  return markRaw(BubbleItemImageHref);
                },
              },
            },
            {
              priority: 110,
              component: markRaw(BlockActionSeparator),
            },
            {
              priority: 120,
              props: {
                icon: markRaw(MdiDeleteForeverOutline),
                title: i18n.global.t("editor.common.button.delete"),
                action: ({ editor }) => {
                  deleteNode(Image.name, editor);
                },
              },
            },
          ],
        };
      },
      getDraggable() {
        return {
          getRenderContainer({ dom, view }): DragSelectionNodeType {
            let container = dom;
            while (container && container.tagName !== "P") {
              container = container.parentElement as HTMLElement;
            }
            if (container) {
              container = container.firstElementChild
                ?.firstElementChild as HTMLElement;
            }
            let node: PMNode | undefined;
            if (container.firstElementChild) {
              const pos = view.posAtDOM(container.firstElementChild, 0);
              const $pos = view.state.doc.resolve(pos);
              node = $pos.node();
            }

            return {
              node: node,
              el: container as HTMLElement,
              dragDomOffset: {
                y: -5,
              },
            };
          },
        };
      },
    };
  },
  renderHTML({ HTMLAttributes }) {
    if (HTMLAttributes.href) {
      return [
        "a",
        { href: HTMLAttributes.href },
        ["img", mergeAttributes(HTMLAttributes)],
      ];
    }
    return ["img", mergeAttributes(HTMLAttributes)];
  },
});

const handleSetTextAlign = (
  editor: Editor,
  align: "left" | "center" | "right" | "justify"
) => {
  editor.chain().focus().setTextAlign(align).run();
};

export default Image;
